package com.well.register.event;

import com.alibaba.fastjson.JSONObject;
import com.well.register.console.domain.Job;
import com.well.register.data.DataCenter;
import com.well.rpc.model.EventType;
import com.well.rpc.model.RegisterModel;
import com.well.rpc.model.TransData;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.util.concurrent.ScheduledFuture;

/**
 * <p>
 *     处理客户端事务
 * </p>
 *
 * @author weedo
 * @since 2022/8/7
 */
@Slf4j
public class ServerHandler {

    /**
     * 根据context获取到远端地址
     * @param channelHandlerContext context
     */
    public static String getRemoteAddress(ChannelHandlerContext channelHandlerContext) {
        return channelHandlerContext.channel().remoteAddress().toString();
    }

    /**
     * 获取channel注册模型
     * @param channelHandlerContext context
     * @return 注册模型
     */
    public static RegisterModel channelRegisterModel(ChannelHandlerContext channelHandlerContext) {
        String remoteAddress = getRemoteAddress(channelHandlerContext);
        return DataCenter.getRegisterModel(remoteAddress);
    }

    /**
     * 组装消息
     * @return
     */
    private static TransData getTransData(EventType type, Object msg) {
        TransData transData = new TransData();
        transData.setType(type);
        transData.setJsonData(JSONObject.toJSONString(msg));
        return transData;
    }

    /**
     * 向客户端发送请求
     * @param registerModel registerModel
     * @param msg msg
     */
    public static boolean writeToClient(RegisterModel registerModel, Object msg, EventType eventType) {
        ChannelHandlerContext channelHandlerContext = DataCenter.getChannelHandlerContext(registerModel.getNameSpace(), registerModel.getGroup(),
                registerModel.getServerName());
        if (channelHandlerContext == null) {
            return false;
        }
        writeToClient(channelHandlerContext, msg, eventType);
        return true;
    }

    public static void writeToClient(ChannelHandlerContext channelHandlerContext, Object msg, EventType eventType) {
        channelHandlerContext.writeAndFlush(getTransData(eventType, msg));
    }

    private static String jobKey(RegisterModel registerModel, String jobName) {
        StringBuilder sb = new StringBuilder();
        sb.append(registerModel.getNameSpace())
                .append(":")
                .append(registerModel.getGroup())
                .append(":")
                .append(registerModel.getServerName())
                .append(":")
                .append(jobName);
        return sb.toString();
    }

    /**
     * 用做后期取消定时任务
     * @param future future
     */
    public static void saveScheduledFuture(ScheduledFuture future, RegisterModel registerModel, String jobInfo) {
        saveScheduledFuture( future, jobKey(registerModel, jobInfo));
    }

    public static void saveScheduledFuture(ScheduledFuture future, String jobInfo) {
        DataCenter.saveScheduleFuture(jobInfo, future);
    }
    /**
     * 获取定时任务future
     */
    public static ScheduledFuture getScheduledFuture(RegisterModel registerModel, String jobName) {
        return getScheduledFuture(jobKey(registerModel, jobName));
    }
    /**
     * 获取定时任务future
     */
    public static ScheduledFuture getScheduledFuture(String jobInfo) {
        return DataCenter.getScheduleFuture(jobInfo);
    }

    public static void cancelScheduledFuture(RegisterModel registerModel, String jobName) {
        String jobKey = jobKey(registerModel, jobName);
        cancelScheduledFuture(jobKey);
    }

    /**
     * 取消任务
     * @param jobInfo
     */
    public static void cancelScheduledFuture(String jobInfo) {
        log.warn("Cancel Job " + jobInfo );
        ScheduledFuture scheduledFuture = getScheduledFuture(jobInfo);
        Assert.notNull(scheduledFuture, "Null is not operate.");
        scheduledFuture.cancel(false);
        DataCenter.removeScheduleFuture(jobInfo);
    }

    /**
     * 发送异常信息
     * @param channelHandlerContext
     * @param message
     */
    public static void exception(ChannelHandlerContext channelHandlerContext, Object message){
        writeToClient(channelHandlerContext, message, EventType.EXCEPTION);
    }
}
